var xpGlobal = {
    prefixCount : 1,
    nsPrefixList : [],
    xpathList : [],
    MAX_XPATHS : 20,
    aborted : false,
    hasMaxLimitForXPaths : true
};

String.prototype.trim = function()
{
    return this.replace(/^\s+|\s+$/g, "");
};

function XPathUtil()
{
}

XPathUtil.setNSPrefixes = function(nsPrefixListArg)
{
    xpGlobal.nsPrefixList = nsPrefixListArg;
    xpGlobal.prefixCount = 1;
};

XPathUtil.extractXPathsfromXML = function(xmlNode, parentXPath, hasMaxLimitForXPaths)
{
    xpGlobal.xpathList = [];
    xpGlobal.aborted = false;
    xpGlobal.hasMaxLimitForXPaths = hasMaxLimitForXPaths;
    collectPredefinedPrefixes(xmlNode);
    collectGeneratedPrefixes(xmlNode);
    collectXPaths(xmlNode, parentXPath);
    return xpGlobal;
};

function removeAutoGeneratedPrefix(prefixPairs)
{
    for ( var prefix in prefixPairs)
    {
        if (prefix.search(/nsp000/) == 0)
        {
            delete prefixPairs[prefix];
        }
    }
}

XPathUtil.getParamNameFromXPath = function(xpath)
{
    var lastToken = xpath.substring(xpath.lastIndexOf("/") + 1);
    var name;
    if (lastToken.indexOf(":") != -1) // contains namespace
    {
        name = lastToken.substring(lastToken.indexOf(":") + 1);
    }
    else
    {
        if (lastToken.indexOf("@") != -1) // contains attribute
        {
            name = lastToken.substring(lastToken.indexOf("@") + 1);
        }
        else
        {
            name = lastToken;
        }
    }
    return name;
};

XPathUtil.initializeNSPrefixes = function()
{
    xpGlobal.prefixCount = 1;
    xpGlobal.nsPrefixList = [];

};

function collectXPaths(xmlNode, parentXPath)
{
    if (xpGlobal.aborted)
    {
        return;
    }
    var xpath;
    var nodeName = xmlNode.nodeName;
    var nodeType = xmlNode.nodeType;
    if ((nodeType != 1 && nodeType != 2) || (nodeType == 2 && (nodeName == "xmlns" || nodeName.indexOf("xmlns:") == 0)))
    {
        return;
    }
    if (nodeName.indexOf(":") == -1)
    {
        var namespace = xmlNode.namespaceURI;
        if (namespace && namespace != "")
        {
            var prefix = getPrefix(namespace);
            if (!prefix)
            {
                prefix = generatePrefix();
                xpGlobal.nsPrefixList[prefix] = namespace;
            }
            nodeName = prefix + ":" + nodeName;
        }
    }
    if (nodeType == 1)
    {
        xpath = parentXPath + "/" + nodeName;
        var childNodes = xmlNode.childNodes;
        for ( var i = 0; i < childNodes.length; i++)
        {
            collectXPaths(childNodes[i], xpath);
        }
        var attributeNodes = xmlNode.attributes;
        for ( var i = 0; i < attributeNodes.length; i++)
        {
            collectXPaths(attributeNodes[i], xpath);
        }
        if (childNodes.length == 0 || (childNodes.length == 1 && childNodes[0].nodeType == 3))
        {
            addXPath(xpath);
        }
    }
    else
        if (nodeType == 2)
        {
            xpath = parentXPath + "/@" + nodeName;
            addXPath(xpath);
        }
}

function addXPath(newXpath)
{
    if (xpGlobal.hasMaxLimitForXPaths && xpGlobal.xpathList.length >= xpGlobal.MAX_XPATHS)
    {
        xpGlobal.aborted = true;
    }
    else
    {
        xpGlobal.xpathList.push(newXpath);
    }
}

function getPrefix(namespace)
{
    var nsPrefixList = xpGlobal.nsPrefixList;
    for ( var prefix in nsPrefixList)
    {
        if (nsPrefixList[prefix] == namespace)
        {
            return prefix;
        }
    }
    return null;
}

function generatePrefix()
{
    var prefixCount = xpGlobal.prefixCount;
    var nsPrefixList = xpGlobal.nsPrefixList;
    var newPrefix = "nsp000" + (prefixCount++);
    while (nsPrefixList[newPrefix])
    {
        newPrefix = "nsp000" + (prefixCount++);
    }
    xpGlobal.prefixCount = prefixCount;
    return newPrefix;
}

function collectPredefinedPrefixes(xmlNode)
{
    var nodeName = xmlNode.nodeName;
    var nodeType = xmlNode.nodeType;
    if (nodeType == 2)
    {
        if (nodeName.indexOf("xmlns:") == 0)
        {
            var prefixname = nodeName.substr(6);
            var namespace = xmlNode.value;
            xpGlobal.nsPrefixList[prefixname] = namespace;

        }
    }
    else
    {
        if (nodeType == 1)
        {
            var childNodes = xmlNode.childNodes;
            for ( var i = 0; i < childNodes.length; i++)
            {
                collectPredefinedPrefixes(childNodes[i]);
            }
            var attributeNodes = xmlNode.attributes;
            for ( var i = 0; i < attributeNodes.length; i++)
            {
                collectPredefinedPrefixes(attributeNodes[i]);
            }
        }
    }
}

function collectGeneratedPrefixes(xmlNode)
{
    var nodeName = xmlNode.nodeName;
    var nodeType = xmlNode.nodeType;
    if (nodeType == 2)
    {
        if (nodeName == "xmlns")
        {
            var namespace = xmlNode.value;
            var prefix = getPrefix(namespace);
            if (!prefix)
            {
                prefix = generatePrefix();
                xpGlobal.nsPrefixList[prefix] = namespace;
            }
        }
    }
    else
    {
        if (nodeType == 1)
        {
            var childNodes = xmlNode.childNodes;
            for ( var i = 0; i < childNodes.length; i++)
            {
                collectGeneratedPrefixes(childNodes[i]);
            }
            var attributeNodes = xmlNode.attributes;
            for ( var i = 0; i < attributeNodes.length; i++)
            {
                collectGeneratedPrefixes(attributeNodes[i]);
            }
        }
    }
}
